package part1basiclock;

/**
 * @description: 生产者消费者问题。while替代if可解决虚假唤醒问题
 * @author: zhang hang
 * @date: 2024/3/14 22:48.
 * @version: 1.0
 */
public class TestLock03 {

    public static void main(String[] args) {

        Data data = new Data();

        new Thread(() -> {
            for (int i = 0; i < 30; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();


        new Thread(() -> {
            for (int i = 0; i < 30; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();

        new Thread(() -> {
            for (int i = 0; i < 30; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "C").start();

        new Thread(() -> {
            for (int i = 0; i < 30; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "D").start();
    }

}


class Data {
    private int number = 0;


    // +1
    public synchronized void increment() throws InterruptedException {
        // 这里要用while，if在四个线程情况下有虚假唤醒问题。
        while (number != 0) {
            this.wait();
        }

        number++;

        System.out.println(Thread.currentThread().getName() + "=>" + number);

        // 通知其他线程
        this.notifyAll();
    }

    // -1
    public synchronized void decrement() throws InterruptedException {
        // 这里要用while，if在四个线程情况下有虚假唤醒问题。
        while (number != 1) {
            this.wait();
        }

        number--;

        System.out.println(Thread.currentThread().getName() + "=>" + number);

        // 通知其他线程
        this.notifyAll();
    }
}